﻿using System;
using System.Collections.Generic;
using System.Text;
using ActiproSoftware.SyntaxEditor;
using ActiproSoftware.SyntaxEditor.Addons.DotNet.Ast;

namespace WindowsUserControl.Codes
{
    /// <summary>
    /// Represents a function declaration.
    /// </summary>
    public class FunctionDeclaration : AstNode, ICollapsibleNode
    {

        private int blockEndOffset = -1;
        private int blockStartOffset = -1;

        /// <summary>
        /// Gets the context ID for the block statement.
        /// </summary>
        public const byte BlockStatementContextID = AstNode.AstNodeContextIDBase;

        /// <summary>
        /// Gets the context ID for the name.
        /// </summary>
        public const byte NameContextID = AstNode.AstNodeContextIDBase + 1;

        /// <summary>
        /// Gets the context ID for the collection of parameters.
        /// </summary>
        public const byte ParameterContextID = AstNode.AstNodeContextIDBase + 2;

        /// <summary>
        /// Gets the minimum context ID that should be used in your code for AST nodes inheriting this class.
        /// </summary>
        /// <remarks>
        /// Base all your context ID constants off of this value.
        /// </remarks>
        protected const byte FunctionDeclarationContextIDBase = AstNode.AstNodeContextIDBase + 3;

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Initializes a new instance of the <c>FunctionDeclaration</c> class. 
        /// </summary>
        public FunctionDeclaration() { }

        /// <summary>
        /// Initializes a new instance of the <c>FunctionDeclaration</c> class. 
        /// </summary>
        /// <param name="textRange">The <see cref="TextRange"/> of the AST node.</param>
        public FunctionDeclaration(TextRange textRange) : base(textRange) { }

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Accepts the specified visitor for visiting this node.
        /// </summary>
        /// <param name="visitor">The visitor to accept.</param>
        /// <remarks>This method is part of the visitor design pattern implementation.</remarks>
        protected override void AcceptCore(AstVisitor visitor)
        {
            if (visitor.OnVisiting(this))
            {
                // Visit children
                if (this.ChildNodeCount > 0)
                    this.AcceptChildren(visitor, this.ChildNodes);
            }
            visitor.OnVisited(this);
        }

        /// <summary>
        /// Gets the image index that is applicable for displaying this node in a user interface control.
        /// </summary>
        /// <value>The image index that is applicable for displaying this node in a user interface control.</value>
        public override int ImageIndex
        {
            get
            {
                return (System.Int32)ActiproSoftware.Products.SyntaxEditor.IconResource.PublicMethod;
            }
        }

        /// <summary>
        /// Gets the <see cref="SimpleNodeType"/> that identifies the type of node.
        /// </summary>
        /// <value>The <see cref="SimpleNodeType"/> that identifies the type of node.</value>
        public override SimpleNodeType NodeType
        {
            get
            {
                return SimpleNodeType.FunctionDeclaration;
            }
        }

        /// <summary>
        /// Gets or sets the block statement.
        /// </summary>
        /// <value>The block statement.</value>
        public BlockStatement BlockStatement
        {
            get
            {
                return this.GetChildNode(FunctionDeclaration.BlockStatementContextID) as BlockStatement;
            }
            set
            {
                this.ChildNodes.Replace(value, FunctionDeclaration.BlockStatementContextID);
            }
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public Identifier Name
        {
            get
            {
                return this.GetChildNode(FunctionDeclaration.NameContextID) as Identifier;
            }
            set
            {
                this.ChildNodes.Replace(value, FunctionDeclaration.NameContextID);
            }
        }

        /// <summary>
        /// Gets the collection of parameters.
        /// </summary>
        /// <value>The collection of statements.</value>
        public IAstNodeList Parameters
        {
            get
            {
                return new AstNodeListWrapper(this, FunctionDeclaration.ParameterContextID);
            }
        }

        /// <summary>
        /// Gets the offset at which the outlining node ends.
        /// </summary>
        /// <value>The offset at which the outlining node ends.</value>
        int ICollapsibleNode.EndOffset
        {
            get
            {
                return blockEndOffset;
            }
        }

        /// <summary>
        /// Gets whether the node is collapsible.
        /// </summary>
        /// <value>
        /// <c>true</c> if the node is collapsible; otherwise, <c>false</c>.
        /// </value>
        bool ICollapsibleNode.IsCollapsible
        {
            get
            {
                return (blockStartOffset != -1) && ((blockStartOffset < blockEndOffset) || (blockEndOffset == -1));
            }
        }

        /// <summary>
        /// Gets the offset at which the outlining node starts.
        /// </summary>
        /// <value>The offset at which the outlining node starts.</value>
        int ICollapsibleNode.StartOffset
        {
            get
            {
                return blockStartOffset;
            }
        }

        /// <summary>
        /// Gets whether the outlining indicator should be visible for the node.
        /// </summary>
        /// <value>
        /// <c>true</c> if the outlining indicator should be visible for the node; otherwise, <c>false</c>.
        /// </value>
        bool IOutliningNodeParseData.IndicatorVisible
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets whether the outlining node is for a language transition.
        /// </summary>
        /// <value>
        /// <c>true</c> if the outlining node is for a language transition; otherwise, <c>false</c>.
        /// </value>
        bool IOutliningNodeParseData.IsLanguageTransition
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Gets or sets the end character offset of the end block delimiter in the original source code that generated the AST node.
        /// </summary>
        /// <value>The end character offset of the end block delimiter in the original source code that generated the AST node.</value>
        /// <remarks>
        /// This value may be <c>-1</c> if there is no source code information for the end character offset.
        /// </remarks>
        public int BlockEndOffset
        {
            get
            {
                return blockEndOffset;
            }
            set
            {
                blockEndOffset = value;
            }
        }

        /// <summary>
        /// Gets or sets the start character offset of the start block delimiter in the original source code that generated the AST node.
        /// </summary>
        /// <value>The start character offset of the start block delimiter in the original source code that generated the AST node.</value>
        /// <remarks>
        /// This value may be <c>-1</c> if there is no source code information for the start character offset.
        /// </remarks>
        public int BlockStartOffset
        {
            get
            {
                return blockStartOffset;
            }
            set
            {
                blockStartOffset = value;
            }
        }

        /// <summary>
        /// Gets text representing the node that can be used for display, such as in a document outline.
        /// </summary>
        /// <value>Text representing the node that can be used for display, such as in a document outline.</value>
        public override string DisplayText
        {
            get
            {
                StringBuilder text = new StringBuilder();
                text.Append("Function ");
                text.Append(this.Name.Text);
                text.Append("(");
                IAstNodeList parameters = this.Parameters;
                for (int index = 0; index < parameters.Count; index++)
                {
                    if (index > 0)
                        text.Append(", ");
                    text.Append(((Identifier)parameters[index]).Text);
                }
                text.Append(")");
                return text.ToString();
            }
        }

        /// <summary>
        /// Gets the character offset at which to navigate when the editor's caret should jump to the text representation of the AST node.
        /// </summary>
        /// <value>The character offset at which to navigate when the editor's caret should jump to the text representation of the AST node.</value>
        public override int NavigationOffset
        {
            get
            {
                Identifier name = this.Name;
                if ((name != null) && (name.HasStartOffset))
                    return name.NavigationOffset;
                else
                    return base.NavigationOffset;
            }
        }

    }
}
